package com.itheima.leetcode.od.b.logicalsimulation;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;

/**
 * (C卷,100分)- 德州扑克（Java & JS & Python）
 * <p>
 * 题目描述
 * <p>
 * 五张牌，每张牌由牌大小和花色组成，牌大小2~10、J、Q、K、A，牌花色为红桃、黑桃、梅花、方块四种花色之一。
 * <p>
 * 判断牌型:
 * <p>
 * 牌型1，同花顺：同一花色的顺子，如红桃2红桃3红桃4红桃5红桃6。
 * <p>
 * 牌型2，四条：四张相同数字 + 单张，如红桃A黑桃A梅花A方块A + 黑桃K。
 * <p>
 * 牌型3，葫芦：三张相同数字 + 一对，如红桃5黑桃5梅花5 + 方块9梅花9。
 * <p>
 * 牌型4，同花：同一花色，如方块3方块7方块10方块J方块Q。
 * <p>
 * 牌型5，顺子：花色不一样的顺子，如红桃2黑桃3红桃4红桃5方块6。
 * <p>
 * 牌型6，三条：三张相同+两张单。
 * <p>
 * 说明：
 * <p>
 * （1）五张牌里不会出现牌大小和花色完全相同的牌。
 * <p>
 * （2）编号小的牌型较大，如同花顺比四条大，依次类推。
 * <p>
 * （3）包含A的合法的顺子只有10 J Q K A和A 2 3 4 5;类似K A 2 3 4的序列不认为是顺子。
 * <p>
 * 输入描述
 * <p>
 * 输入由5行组成，每行为一张牌大小和花色，牌大小为2~10、J、Q、K、A，花色分别用字符H、S、C、D表示红桃、黑桃、梅花、方块。
 * <p>
 * 输出描述
 * <p>
 * 输出牌型序号，5张牌符合多种牌型时，取最大的牌型序号输出。
 * <p>
 * 用例
 * <p>
 * 输入	4 H
 * <p>
 * 5 S
 * <p>
 * 6 C
 * <p>
 * 7 D
 * <p>
 * 8 D
 * <p>
 * 输出	5
 * 说明	4 5 6 7 8构成顺子，输出5
 * <p>
 * 输入	9 S
 * <p>
 * 5 S
 * <p>
 * 6 S
 * <p>
 * 7 S
 * <p>
 * 8 S
 * <p>
 * 输出	1
 * 说明	既是顺子又是同花，输出1，同花顺
 * <p>
 * 题目解析
 * <p>
 * 这道题应该是一道逻辑题，这道题目输入了五张牌，然后我们需要对这五张牌进行六种情况的分析，并且分析有优先级：
 * <p>
 * 是否为同花顺
 * 是否为四条
 * 是否为葫芦
 * 是否同花
 * 是否为顺子
 * 是否为三条
 * 若满足了前面，则后面的就不需要再判断了。
 * <p>
 * 另外，同花顺情况判断，其实就是 同花 + 顺子，因此在写代码时可以再拆下代码。
 * <p>
 * 上面六种情况的判断，其实可以将五张牌的大小和花色分开来，分别检查。因此我将输入的五张牌的大小存入nums数组，花色存入colors数组。
 * <p>
 * 其中顺子的判断，其实不关心花色，只关心牌大小，我们只需要为牌定义好大小后，进行大小升序排序，若后面一张牌的大小总是比其前面一张牌大1，则就是顺子。
 * <p>
 * 另外还一个特殊情况，即‘A2345’也是顺子，这里我们给A定义的大小是14，因此nums升序排序后，只需要判断nums.join('')是否和'2345A'相等，即可判定为顺子。
 * <p>
 * 而四条的判断，也不关心花色，只关系牌大小，四条即 四个相同牌大小，一个不同牌大小。这个很好判断，我这里的方案是，new Set(nums)来去重，若去重后不是两张牌，那么就肯定不是四条，若有两张牌，则任取一张，看在nums中有几个，若为1个或4个，则可以判定为四条。
 * <p>
 * 葫芦、三条的判定和四条类似。
 * <p>
 * 同花的判定，即new Set(colors)，若去重后只有一个花色，则判定为同花。
 * <p>
 * 另外，本题没有说如果输入的五张牌都不满足上面六种情况时，该输出啥，一个可能是，用例保证输入的五张牌肯定满足上面六种情况之一，因此不需要考虑这种异常场景。一个可能是，出题人遗漏了这种情况的输出说明，我这里把不满足上面六种情况的输出自定义为0.
 */
public class TexasHoldem {
    public static void main(String[] args) {
        /*Scanner sc = new Scanner(System.in);

        String[] nums = new String[5];
        String[] colors = new String[5];

        for (int i = 0; i < 5; i++) {
            nums[i] = sc.next();
            colors[i] = sc.next();
        }*/

        String input = "4 H\n5 S\n6 C\n7 D\n8 D";

        String[] nums = Arrays.stream(input.split("\n"))
                .map(s -> s.split(" ")[0])
                .toArray(String[]::new);
        String[] colors = Arrays.stream(input.split("\n"))
                .map(s -> s.split(" ")[1])
                .toArray(String[]::new);

        System.out.println(getResult(nums, colors));
    }

    public static int getResult(String[] nums, String[] colors) {
        Arrays.sort(nums, (a, b) -> cards(a) - cards(b));

        if (isShunzi(nums) && isTonghua(colors)) {
            return 1;
        } else if (isSitiao(nums)) {
            return 2;
        } else if (isHulu(nums)) {
            return 3;
        } else if (isTonghua(colors)) {
            return 4;
        } else if (isShunzi(nums)) {
            return 5;
        } else if (isSantiao(nums)) {
            return 6;
        } else {
            return 0;
        }
    }

    // 牌大小 映射为 数值
    public static int cards(String num) {
        switch (num) {
            case "J":
                return 11;
            case "Q":
                return 12;
            case "K":
                return 13;
            case "A":
                return 14;
            default:
                return Integer.parseInt(num);
        }
    }

    // 顺子
    public static boolean isShunzi(String[] nums) {
        if ("2345A".equals(String.join("", nums))) {
            return true;
        }

        for (int i = 1; i < nums.length; i++) {
            int num1 = cards(nums[i - 1]);
            int num2 = cards(nums[i]);
            if (num1 + 1 != num2) {
                return false;
            }
        }

        return true;
    }

    // 同花
    public static boolean isTonghua(String[] colors) {
        // 同花牌的所有花色都一样
        return new HashSet<String>(Arrays.asList(colors)).size() == 1;
    }

    // 四条
    public static boolean isSitiao(String[] nums) {
        // 四条由两部分组成，一个部分四张相同牌，一个部分一张牌
        return countNums(nums, 2, 4);
    }

    // 葫芦
    public static boolean isHulu(String[] nums) {
        // 葫芦由两部分组成，一个部分三张牌相同，一个部分两张牌相同
        return countNums(nums, 2, 3);
    }

    // 三条
    public static boolean isSantiao(String[] nums) {
        // 三条由三部分组成，第一个部分由三张相同牌组成，第二个，第三个部分分别是两种不同的牌
        return countNums(nums, 3, 3);
    }

    private static boolean countNums(String[] nums, int partCount, int maxSameNumCount) {
        HashMap<String, Integer> count = new HashMap<>();

        for (String num : nums) {
            count.put(num, count.getOrDefault(num, 0) + 1);
        }

        if (count.keySet().size() != partCount) {
            return false;
        }

        return count.containsValue(maxSameNumCount);
    }
}